#include "benchmark.h"
#include "result.h"
#include <stdio.h>


//
// IResultWriter
//

IResultWriter::~IResultWriter()
{
}


IBenchmark::~IBenchmark()
{
}

//
// CResultWriterFile
//

CResultWriterFile::CResultWriterFile(FILE *outfile)
{
    m_Out = outfile;
}


void CResultWriterFile::WriteInfo(const RESULTSFILEINFO *info)
{
    info->Print(m_Out);
}


void CResultWriterFile::BeginModule(const char *modulename)
{
    fprintf(m_Out, "\n<module>\nmodulename = %s\n\n", modulename);
}


void CResultWriterFile::EndModule()
{
    fprintf(m_Out, "</module>\n");
}


void CResultWriterFile::WriteNode(const char *name, float value)
{
    fprintf(m_Out, "%-45s = %.12f\n", name, value);
}

//
// CResultWriterMemory
//


CResultWriterMemory::CResultWriterMemory()
{
    m_Verbose = false;
}


void CResultWriterMemory::WriteInfo(const RESULTSFILEINFO *info)
{
    m_Info = *info;

    if (m_Verbose)
    {
        puts("\n");
        info->Print(stdout);
    }
}


void CResultWriterMemory::BeginModule(const char *modulename)
{
    MODULE m;    
    m.name = modulename;
    m_Modules.push_back(m);    

    if (m_Verbose)
        printf("<%s>\n", modulename);
}


void CResultWriterMemory::EndModule()
{    
}


void CResultWriterMemory::WriteNode(const char *name, float value)
{
    assert(m_Modules.size());

    MODULE::NODE n;
    n.name = name;
    n.value = value;

    m_Modules.back().nodes.push_back(n);    

    if (m_Verbose)
        printf("    %-40s = %.8f\n", name, value);
}


void CResultWriterMemory::WriteConfig(const char *filename)
{
    FILE *f = fopen(filename, "wt");

    if (f == NULL)
    {
        printf("[CResultWriterMemory::WriteConfig] Nem tudtam megnyitni irasra: \"%s\"\n", filename);
        return;
    }

    for (uint i=0; i<m_Modules.size(); i++)
    {   
        fprintf(f, "<module>\n");
        fprintf(f, "modulename = \"%s\"\n", m_Modules[i].name.c_str());
        fprintf(f, "longname = \"Module: %s\" // TODO: irj leirast\n", m_Modules[i].name.c_str());
        fprintf(f, "moduleweight = %.6f\n\n", 1.0 / m_Modules[i].nodes.size());

        for (uint j=0; j<m_Modules[i].nodes.size(); j++)
        {
            const MODULE::NODE &node = m_Modules[i].nodes[j];

            if (node.value <= 0)
            {
                puts("\n==================================================================================");
                printf("Egy teszt eredmenye ervenytelen, igy nem lehet config fajlt irni! (%s)\n", node.name.c_str());
                puts("====================================================================================");
                fclose(f);
                exit(-1);
            }

            fprintf(f, "%s = %.6f\n", node.name.c_str(), 1.0 / node.value);
        }

        fprintf(f, "</module>\n\n");
    }

    fclose(f);
}


void CResultWriterMemory::Merge(const CResultWriterMemory *results, int result_count, IResultWriter *out)
{
    if (result_count == 0)
        return;

    out->WriteInfo(&results[0].m_Info);         // a 0 is ugyanaz, mint a tobbi

    for (uint m=0; m<results[0].m_Modules.size(); m++)
    {
        const MODULE &module = results[0].m_Modules[m];

        out->BeginModule(module.name.c_str());

        for (uint n=0; n<module.nodes.size(); n++)
        {
            const MODULE::NODE &node = module.nodes[n];

            double sum = 0;

            for (int i=0; i<result_count; i++)
            {
                float val = results[i].m_Modules[m].nodes[n].value;
                sum += val;
            }

            out->WriteNode(node.name.c_str(), (float)(sum / result_count));
        }

        out->EndModule();
    }
}


//
// CBenchmark
//

CBenchmark::CBenchmark(const CCmdlineArgs *args)
{
    m_Args = args;
}


CBenchmark::~CBenchmark()
{
    Cleanup();
}


void CBenchmark::Cleanup()
{
    for (unsigned i=0; i<m_Benchmarks.size(); i++)
        SDELETE(m_Benchmarks[i]);

    m_Benchmarks.clear();
    m_Args = NULL;
}


void CBenchmark::Add(IBenchmark *p)
{
    m_Benchmarks.push_back(p);
}


void CBenchmark::Run(const RESULTSFILEINFO *info, IResultWriter *results)
{
    results->WriteInfo(info);

    for (uint i=0; i<m_Benchmarks.size(); i++)
    {
        try
        {
            results->BeginModule(m_Benchmarks[i]->GetName());
            m_Benchmarks[i]->Run(results, m_Args);
            results->EndModule();
        }
        catch (...)
        {
            printf("(exception) Hiba a \"%s\" futtatasakor\n", m_Benchmarks[i]->GetName());
        }
    }
}
